use proc_macro::TokenStream;
use syn::Data::Struct;
use syn::{DeriveInput, Field};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;

#[proc_macro_derive(Builder)]
pub fn derive(input: TokenStream) -> TokenStream {
    let st = syn::parse_macro_input!(input as syn::DeriveInput);
    match do_expand(&st){
        Ok(token_stream) => token_stream.into(),
        Err(e) => e.to_compile_error().into()
    }
}
fn generate_builder_struct_fields_def(st: &syn::DeriveInput)->syn::Result<proc_macro2::TokenStream>{
    let punctuated_fields = get_fields_from_derive_input(&st)?;
    let idents: Vec<_> = punctuated_fields.iter().map(|field| &field.ident).collect();
    let types: Vec<_> = punctuated_fields.iter().map(|field| &field.ty).collect();
    quote::quote! (
        #( #idents: core::Option<#types>),*
    );
    todo!()
}

fn do_expand(st: &syn::DeriveInput)->syn::Result<proc_macro2::TokenStream>{
    //1. 获取结构体名称
    let struct_name_literal = st.ident.to_string();
    //2. Builder名称,标识符
    let builder_name_literal = format!("{struct_name_literal}Builder");
    let builder_name_ident = syn::Ident::new(builder_name_literal.as_str(),st.span());
    let struct_name_ident = &st.ident;
    //3. 生成代码

    let ret = quote::quote!(
         pub struct #builder_name_ident {
            //TODO
        }

        impl #struct_name_ident {
            pub fn builder() -> #builder_name_ident {
                #builder_name_ident {
                    //TODO
                }
            }
        }
    );
    Ok(ret)
}

fn get_fields_from_derive_input(st: &DeriveInput)->syn::Result<&Punctuated<Field, syn::Token![,]>>{
    if let syn::Data::Struct(
        syn::DataStruct{
            fields: syn::Fields::Named(
                syn::FieldsNamed{
                    ref named,..
                }
            ),..
        }
    ) = &st.data{
       Ok(named)
    }else{
        Err(syn::Error::new(st.span(),"Get fields from DriveInput failed，Must Define On Struct"))
    }
}